// First, resolve the package's *listed* dependencies, as well as
// downloading and updating all remotes and such.
- try!(ops::resolve_and_fetch(&mut registry, package));
+ try!(ops::resolve_pkg(&mut registry, package));
// Second, resolve with precisely what we're doing. Filter out
// transitive dependencies if necessary, specify features, handle
let mut config = try!(Config::new(shell, None, None));
let mut registry = PackageRegistry::new(&mut config);
- try!(resolve_and_fetch(&mut registry, &package));
+ try!(ops::resolve_pkg(&mut registry, &package));
Ok(())
}
-
-/// Finds all the packages required to compile the specified `Package`,
-/// and loads them in the `PackageRegistry`.
-///
-/// Also write the `Cargo.lock` file with the results.
-pub fn resolve_and_fetch(registry: &mut PackageRegistry, package: &Package)
- -> CargoResult<Resolve> {
- let _p = profile::start("resolve and fetch...");
-
- let lockfile = package.get_manifest_path().dir_path().join("Cargo.lock");
- let source_id = package.get_package_id().get_source_id();
- let previous_resolve = try!(ops::load_lockfile(&lockfile, source_id));
- let sources = match previous_resolve {
- Some(ref r) => r.iter().map(|p| p.get_source_id().clone()).collect(),
- None => vec![package.get_package_id().get_source_id().clone()],
- };
- try!(registry.add_sources(sources.as_slice()));
-
- let mut resolved = try!(resolver::resolve(package.get_summary(),
- resolver::ResolveEverything,
- registry));
- match previous_resolve {
- Some(ref prev) => resolved.copy_metadata(prev),
- None => {}
- }
- try!(ops::write_resolve(package, &resolved));
- Ok(resolved)
-}
use serialize::{Encodable, Decodable};
use toml::{mod, Encoder};
+use core::PackageId;
use core::registry::PackageRegistry;
use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
-use core::PackageId;
+use ops;
use sources::{PathSource};
use util::config::{Config};
-use util::{CargoResult, human};
use util::toml as cargo_toml;
+use util::{CargoResult, human};
pub struct UpdateOptions<'a> {
pub shell: &'a mut MultiShell<'a>,
try!(source.update());
let package = try!(source.get_root_package());
let mut config = try!(Config::new(shell, None, None));
-
- let resolve = {
- let mut registry = PackageRegistry::new(&mut config);
- try!(resolver::resolve(package.get_summary(),
- resolver::ResolveEverything,
- &mut registry))
- };
- try!(write_resolve(&package, &resolve));
+ let mut registry = PackageRegistry::new(&mut config);
+ let resolve = try!(ops::resolve_with_previous(&mut registry, &package, None));
+ try!(ops::write_pkg_lockfile(&package, &resolve));
Ok(())
}
try!(source.update());
let package = try!(source.get_root_package());
- let lockfile = package.get_root().join("Cargo.lock");
- let source_id = package.get_package_id().get_source_id();
- let previous_resolve = match try!(load_lockfile(&lockfile, source_id)) {
+ let previous_resolve = match try!(ops::load_pkg_lockfile(&package)) {
Some(resolve) => resolve,
None => return Err(human("A Cargo.lock must exist before it is updated"))
};
resolver::ResolveEverything,
&mut registry));
resolve.copy_metadata(&previous_resolve);
- try!(write_resolve(&package, &resolve));
+ try!(ops::write_pkg_lockfile(&package, &resolve));
return Ok(());
fn fill_with_deps<'a>(resolve: &'a Resolve, dep: &'a PackageId,
}
}
}
-
-pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
- // If there is no lockfile, return none.
- let mut f = match File::open(path) {
- Ok(f) => f,
- Err(_) => return Ok(None)
- };
-
- let s = try!(f.read_to_string());
-
- let table = toml::Table(try!(cargo_toml::parse(s.as_slice(), path)));
- let mut d = toml::Decoder::new(table);
- let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
- Ok(Some(try!(v.to_resolve(sid))))
-}
-
-pub fn write_resolve(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
- let loc = pkg.get_root().join("Cargo.lock");
-
- let mut e = Encoder::new();
- resolve.encode(&mut e).unwrap();
-
- let mut out = String::new();
-
- // Note that we do not use e.toml.to_string() as we want to control the
- // exact format the toml is in to ensure pretty diffs between updates to the
- // lockfile.
- let root = e.toml.find(&"root".to_string()).unwrap();
-
- out.push_str("[root]\n");
- emit_package(root.as_table().unwrap(), &mut out);
-
- let deps = e.toml.find(&"package".to_string()).unwrap().as_slice().unwrap();
- for dep in deps.iter() {
- let dep = dep.as_table().unwrap();
-
- out.push_str("[[package]]\n");
- emit_package(dep, &mut out);
- }
-
- match e.toml.find(&"metadata".to_string()) {
- Some(metadata) => {
- out.push_str("[metadata]\n");
- out.push_str(metadata.to_string().as_slice());
- }
- None => {}
- }
-
- try!(File::create(&loc).write_str(out.as_slice()));
- Ok(())
-}
-
-fn emit_package(dep: &toml::TomlTable, out: &mut String) {
- out.push_str(format!("name = {}\n", lookup(dep, "name")).as_slice());
- out.push_str(format!("version = {}\n", lookup(dep, "version")).as_slice());
-
- if dep.contains_key(&"source".to_string()) {
- out.push_str(format!("source = {}\n", lookup(dep, "source")).as_slice());
- }
-
- if let Some(ref s) = dep.find(&"dependencies".to_string()) {
- let slice = s.as_slice().unwrap();
-
- if !slice.is_empty() {
- out.push_str("dependencies = [\n");
-
- for child in s.as_slice().unwrap().iter() {
- out.push_str(format!(" {},\n", child).as_slice());
- }
-
- out.push_str("]\n");
- }
- out.push_str("\n");
- }
-}
-
-fn lookup<'a>(table: &'a toml::TomlTable, key: &str) -> &'a toml::Value {
- table.find(&key.to_string()).expect(format!("Didn't find {}", key).as_slice())
-}
--- /dev/null
+use std::collections::HashSet;
+use std::io::File;
+
+use serialize::{Encodable, Decodable};
+use toml::{mod, Encoder};
+
+use core::registry::PackageRegistry;
+use core::{MultiShell, Source, Resolve, resolver, Package, SourceId};
+use core::PackageId;
+use sources::{PathSource};
+use util::config::{Config};
+use util::{CargoResult, human};
+use util::toml as cargo_toml;
+
+pub fn load_pkg_lockfile(pkg: &Package) -> CargoResult<Option<Resolve>> {
+ let lockfile = pkg.get_manifest_path().dir_path().join("Cargo.lock");
+ let source_id = pkg.get_package_id().get_source_id();
+ load_lockfile(&lockfile, source_id)
+}
+
+pub fn load_lockfile(path: &Path, sid: &SourceId) -> CargoResult<Option<Resolve>> {
+ // If there is no lockfile, return none.
+ let mut f = match File::open(path) {
+ Ok(f) => f,
+ Err(_) => return Ok(None)
+ };
+
+ let s = try!(f.read_to_string());
+
+ let table = toml::Table(try!(cargo_toml::parse(s.as_slice(), path)));
+ let mut d = toml::Decoder::new(table);
+ let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap();
+ Ok(Some(try!(v.to_resolve(sid))))
+}
+
+pub fn write_pkg_lockfile(pkg: &Package, resolve: &Resolve) -> CargoResult<()> {
+ let loc = pkg.get_root().join("Cargo.lock");
+ write_lockfile(&loc, resolve)
+}
+
+pub fn write_lockfile(dst: &Path, resolve: &Resolve) -> CargoResult<()> {
+ let mut e = Encoder::new();
+ resolve.encode(&mut e).unwrap();
+
+ let mut out = String::new();
+
+ // Note that we do not use e.toml.to_string() as we want to control the
+ // exact format the toml is in to ensure pretty diffs between updates to the
+ // lockfile.
+ let root = e.toml.find(&"root".to_string()).unwrap();
+
+ out.push_str("[root]\n");
+ emit_package(root.as_table().unwrap(), &mut out);
+
+ let deps = e.toml.find(&"package".to_string()).unwrap().as_slice().unwrap();
+ for dep in deps.iter() {
+ let dep = dep.as_table().unwrap();
+
+ out.push_str("[[package]]\n");
+ emit_package(dep, &mut out);
+ }
+
+ match e.toml.find(&"metadata".to_string()) {
+ Some(metadata) => {
+ out.push_str("[metadata]\n");
+ out.push_str(metadata.to_string().as_slice());
+ }
+ None => {}
+ }
+
+ try!(File::create(dst).write_str(out.as_slice()));
+ Ok(())
+}
+
+fn emit_package(dep: &toml::TomlTable, out: &mut String) {
+ out.push_str(format!("name = {}\n", lookup(dep, "name")).as_slice());
+ out.push_str(format!("version = {}\n", lookup(dep, "version")).as_slice());
+
+ if dep.contains_key(&"source".to_string()) {
+ out.push_str(format!("source = {}\n", lookup(dep, "source")).as_slice());
+ }
+
+ if let Some(ref s) = dep.find(&"dependencies".to_string()) {
+ let slice = s.as_slice().unwrap();
+
+ if !slice.is_empty() {
+ out.push_str("dependencies = [\n");
+
+ for child in s.as_slice().unwrap().iter() {
+ out.push_str(format!(" {},\n", child).as_slice());
+ }
+
+ out.push_str("]\n");
+ }
+ out.push_str("\n");
+ }
+}
+
+fn lookup<'a>(table: &'a toml::TomlTable, key: &str) -> &'a toml::Value {
+ table.find(&key.to_string()).expect(format!("Didn't find {}", key).as_slice())
+}
pub use self::cargo_run::run;
pub use self::cargo_new::{new, NewOptions};
pub use self::cargo_doc::{doc, DocOptions};
-pub use self::cargo_generate_lockfile::{generate_lockfile, write_resolve};
-pub use self::cargo_generate_lockfile::{update_lockfile, load_lockfile};
+pub use self::cargo_generate_lockfile::{generate_lockfile};
+pub use self::cargo_generate_lockfile::{update_lockfile};
pub use self::cargo_generate_lockfile::UpdateOptions;
+pub use self::lockfile::{load_lockfile, load_pkg_lockfile};
+pub use self::lockfile::{write_lockfile, write_pkg_lockfile};
pub use self::cargo_test::{run_tests, run_benches, TestOptions};
pub use self::cargo_package::package;
pub use self::registry::{publish, registry_configuration, RegistryConfig};
pub use self::registry::{registry_login, http_proxy, http_handle};
pub use self::registry::{modify_owners, yank};
-pub use self::cargo_fetch::{fetch, resolve_and_fetch};
+pub use self::cargo_fetch::{fetch};
pub use self::cargo_pkgid::pkgid;
+pub use self::resolve::{resolve_pkg, resolve_with_previous};
mod cargo_clean;
mod cargo_compile;
-mod cargo_read_manifest;
-mod cargo_rustc;
-mod cargo_run;
-mod cargo_new;
mod cargo_doc;
+mod cargo_fetch;
mod cargo_generate_lockfile;
-mod cargo_test;
+mod cargo_new;
mod cargo_package;
-mod cargo_fetch;
mod cargo_pkgid;
+mod cargo_read_manifest;
+mod cargo_run;
+mod cargo_rustc;
+mod cargo_test;
+mod lockfile;
mod registry;
+mod resolve;
--- /dev/null
+use std::collections::HashMap;
+
+use semver::VersionReq;
+
+use core::{MultiShell, Package};
+use core::registry::PackageRegistry;
+use core::resolver::{mod, Resolve};
+use core::source::Source;
+use ops;
+use sources::PathSource;
+use util::{CargoResult, Config};
+use util::profile;
+
+/// Resolve all dependencies for the specified `package` using the previous
+/// lockfile as a guide if present.
+///
+/// This function will also generate a write the result of resolution as a new
+/// lockfile.
+pub fn resolve_pkg(registry: &mut PackageRegistry, package: &Package)
+ -> CargoResult<Resolve> {
+ let prev = try!(ops::load_pkg_lockfile(package));
+ let resolve = try!(resolve_with_previous(registry, package, prev.as_ref()));
+ try!(ops::write_pkg_lockfile(package, &resolve));
+ Ok(resolve)
+}
+
+/// Resolve all dependencies for a package using an optional prevoius instance
+/// of resolve to guide the resolution process.
+///
+/// The previous resolve normally comes from a lockfile. This function does not
+/// read or write lockfiles from the filesystem.
+pub fn resolve_with_previous(registry: &mut PackageRegistry,
+ package: &Package,
+ previous: Option<&Resolve>)
+ -> CargoResult<Resolve> {
+ let root = package.get_package_id().get_source_id().clone();
+ try!(registry.add_sources(&[root]));
+
+ match previous {
+ Some(r) => {
+ let v = r.iter().map(|p| p.get_source_id().clone())
+ .collect::<Vec<_>>();
+ try!(registry.add_sources(v.as_slice()));
+ }
+ None => {}
+ };
+
+ let mut resolved = try!(resolver::resolve(package.get_summary(),
+ resolver::ResolveEverything,
+ registry));
+ match previous {
+ Some(r) => resolved.copy_metadata(previous),
+ None => {}
+ }
+ Ok(resolved)
+}